Skip to content

(sidebar): exclude subagents from project-level archive-all - #149

Merged
devsuitup merged 1 commit into
mainfrom
fix/project-archive-all-subagents
Aug 23, 2026
Merged

(sidebar): exclude subagents from project-level archive-all#149
devsuitup merged 1 commit into
mainfrom
fix/project-archive-all-subagents

Conversation

@devsuitup

@devsuitup devsuitup commented Aug 23, 2026

Copy link
Copy Markdown
Owner

Problem

buildProjectsFromCache (session-cache.js) groups every session_cache row by projectPath — subagent rows included. They are indexed from <folder>/<parent>/subagents/agent-*.jsonl and carry the same folder and projectPath as their parent, with parentSessionId set. So the project.sessions array the renderer receives is a flat list of parents and children, and every consumer has to drop the children itself. processProjectSessions does (allSessions.filter(s => !s.parentSessionId)); the DB side does too (getTotalCounts, WHERE parentSessionId IS NULL).

The project header's Archive all sessions button did not:

  • the confirmation prompt counted subagents — "Archive all 87 sessions…" on a project with a handful of real ones;
  • every subagent transcript was archived, so it vanished from under its parent;
  • stopSession was called on any subagent id that happened to be in activePtyIds.

The status bar's N sessions total (renderDefaultStatus) had the same defect, and therefore disagreed with the stats panel's own total for the same data.

Fix

Filter on parentSessionId in both places. Two one-line changes; no behavioural change for top-level sessions.

Tests

test/dom-project-archive-all.test.js — 2 jsdom tests. Verified failing before the fix:

actual: 'Archive all 4 sessions in dev/myproj?'  expected: /Archive all 1 session in /
actual: [ 's-top-1', 's-sub-1', 's-sub-2', 's-sub-orphan' ]  expected: [ 's-top-1' ]

The second test puts all four ids in activePtyIds, so it also pins the stopSession leak.

Full suite: 673 tests, 666 pass, 0 fail, 7 pre-existing skips. ESLint: 0 errors.

renderDefaultStatus is not covered — there is no jsdom harness for app.js. That one line is verified by reading only.

Out of scope

The slug-group archive button has the same class of bug and is handled in #134.

One related defect is documented but not fixed here: when a search matches only subagent transcripts in a project, refreshSidebar narrows sessions to those matches, processProjectSessions filters them all out, and the project drops out of the results entirely. Surfacing it needs a UI decision, not a filter. Written up in .ai/contexts/subagent-observability.md.

Knock-on fixed in the same PR: the project vanished instead

Review caught a regression the two-line filter introduced. Once every top-level session is archived, the surviving subagent rows keep project.sessions non-empty while filtered (top-level only) is empty — so the guard at sidebar.js:442 returned null and the render loop continued before reaching buildSessionsList and its orphan-subagent bucket. Header and orphans both gone: the whole project disappeared from the default view although its data was still there.

Not data loss — "Show Archived" brings it back. But the old behaviour hid this by accident: archiving the children too left project.sessions genuinely empty, so the disappearance was correct. The filter alone turned a correct disappearance into an incorrect one, and systematically, from the first surviving subagent.

The guard now keeps a project that still has indexed subagents and no active filter:

const keepForOrphanSubagents = !anyFilterActive && subagentIndex.size > 0;

subagentIndex is already built two lines above and is the exact object buildSessionsList consults for its orphan bucket — no second mechanism. When filtered is empty, allTopLevelIds is empty by construction, so every indexed subagent is an orphan: size > 0 is the precise "there is something to show", not an approximation. !anyFilterActive carries weight — without it, a starred/running/today filter or an active search would resurface every project owning a subagent, since a subagent satisfies none of those filters.

Both halves are mutation-proven:

without !keepForOrphanSubagents → ✖ project header must survive when unarchived subagents remain
                                    actual: null, expected: true
without !anyFilterActive        → ✖ an active filter with no matching top-level session must still hide the project
                                    actual: {}, expected: null

Guard cases verified unbroken: empty project, project whose top-level sessions are filtered out, empty project under an active filter, _projectMatchedOnly, project with surviving top-level sessions.

Full suite after rework: 685 tests, 678 pass, 0 fail, 7 pre-existing skips. ESLint: 0 errors.

buildProjectsFromCache groups every session_cache row by projectPath,
subagent rows included, so project.sessions is a flat list of parents and
children. The project header's "Archive all sessions" button treated it as
top-level only: it counted subagents in its confirmation prompt, archived
each subagent transcript so it disappeared from under its parent, and
called stopSession on any subagent id present in activePtyIds. This also
makes the bulk button consistent with the per-session archive button, which
never touched children.

Not archiving the children exposes a latent hole in processProjectSessions'
skip guard: the archived parents are gone from project.sessions but the
subagents remain, so filtered is empty while the array is not, and the whole
project dropped out of the default view — header and orphan bucket alike,
the latter living past the render loop's continue. Keep the project when
unarchived subagents remain and no filter is active, so the existing orphan
bucket renders them.

The status bar's session total had the same flat-list defect and disagreed
with the stats panel, which counts WHERE parentSessionId IS NULL.
@devsuitup
devsuitup force-pushed the fix/project-archive-all-subagents branch from 6d67c0a to a761e03 Compare August 23, 2026 20:56
@devsuitup
devsuitup merged commit 54fb8ce into main Aug 23, 2026
7 checks passed
@devsuitup
devsuitup deleted the fix/project-archive-all-subagents branch August 23, 2026 21:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant